package com.fortify.awb.bugtracker;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Arrays;

import com.fortify.awb.BugtrackerPlugin;

/**
 * The Bugzilla Plugin is a simple working example of an implementation of the {@link BugtrackerPlugin} interface.
 * It submits bugs to a server through the system web browser.
 * <br><br>
 * To create your own bug tracker plugin, first identify which bug tracker system you wish to
 * integrate with, and locate the URL of the bug tracker's web interface.
 * <br><br>
 * If your bug tracking software does not provide a web interface, you will need to implement
 * {@link #submit(BugtrackerFields)} in another way. See {@link com.fortify.awb.BugtrackerPlugin} for more details.
 */
public class JiraPlugin implements BugtrackerPlugin {

	/**
	 * The system defined line separator.
	 */
	static final String LINE_SEP = System.getProperty("line.separator");

	/**
	 * The text that's displayed to the user in the list of registered bug trackers
	 */
	@Override
	public String toString() {
		return "Jira Plugin";
	}

	/**
	 * Creates a new {@link BugtrackerFields} collection, creates several Jira-specific fields, and adds
	 * them to the collection
	 */
	public BugtrackerFields getDefaultFields() {

		BugtrackerFields fields = new BugtrackerFields();
		fields.addFieldWithDefaultValue("Jira URL", "http://jira");
		fields.addFieldWithDefaultValue("Reporter", System.getenv().get("USERNAME"));
		fields.addFieldWithDefaultValue("Product", "11016");
		fields.addFieldWithDefaultValue("Component", "15305");
		fields.addFieldWithDefaultValue("Issue Type", "3 - Todo").setPossibleValues(Arrays.asList("1 - Error", "3 - Todo"));
		fields.addFieldWithDefaultValue("Priority", "3").setPossibleValues(Arrays.asList("1", "2", "3", "4"));
		fields.addFieldWithDefaultValue("Assignee", System.getenv().get("USERNAME"));
		return fields;
	}

	/**
	 * Creates a url that submits a form with the necessary information to the Bugzilla
	 * web interface.
	 * <br>
	 * The "Summary" and "Description" properties from the options argument are used to
	 * fill in the "Short Description" and "Comment" fields on the Bugzilla web form.
	 * <br>
	 * All the other form values are automatically filled in from the getDefaultFields()
	 * method.
	 * 
	 * @param options The Bugzilla bug parameters, which already have default fields
	 * from getDefaultFields() filled in, as well as the user specified options
	 * "Summary" and "Description".
	 * @return true if the submission succeeds, or false if the submittal fails.
	 * */
	public boolean submit(BugtrackerFields options) {
		StringBuilder url = new StringBuilder();
		try {
			// the URL begins with the address of the bug submittal form
			url.append("http://jira/secure/CreateIssueDetails.jspa?");

			url.append("pid=" + encodeAsUTF8(options.getField("Product").getValue()));
			url.append("&reporter=" + encodeAsUTF8(options.getField("Reporter").getValue()));
			url.append("&components=" + encodeAsUTF8(options.getField("Component").getValue()));
			url.append("&issuetype=" + options.getField("Issue Type").getValue().charAt(0));
			url.append("&priority=" + (Integer.parseInt(options.getField("Priority").getValue()) + 5));
			url.append("&summary=" + encodeAsUTF8(options.getField("Summary").getValue()));
			url.append("&assignee=" + encodeAsUTF8(options.getField("Assignee").getValue()));
			//			url.append("&description=" + encodeAsUTF8(options.getField("full_desc").getValue()));
		} catch (UnsupportedEncodingException e) {
			// If UTF-8 is not a supported encoding, this invocation will fail.
			// This is not likely to happen on any platform supported by Fortify.
			return false;
		}

		// Send the URL to be opened by the user's system web browser
		return invokeWebBrowser(url.toString());
	}

	/**
	 * Encodes the string content as UTF-8
	 */
	private String encodeAsUTF8(String content) throws UnsupportedEncodingException {
		return URLEncoder.encode(content, "UTF-8");
	}

	/**
	 * Utility method that invokes a supported web browser on the user's system, and instructs
	 * that browser to open the specified URL.
	 * <br>
	 * The following system commands are executed in sequence, until one of them succeeds:
	 * <ul>
	 * 	<li>"rundll32 url.dll,FileProtocolHandler"
		<li>"firefox"
		<li>"mozilla"
		<li>"opera"
		<li>"netscape"
		<li>"open"
	 * </ul>
	 * 
	 * @param url The URL to open with the user's system web browser.
	 * @return true if the system command succeeds, or false if the system command fails.
	 * */
	private boolean invokeWebBrowser(String url) {

		// A set of web browser system commands to try
		String[] browsers = new String[] {

				// Default web browser command on Microsoft Windows
				"rundll32 url.dll,FileProtocolHandler",

				// Various supported web browser executables
				"firefox", "mozilla", "opera", "netscape",

				// Default web browser command on Apple OS X
		"open" };

		// Cycle through the list of browser commands until one succeeds
		for (String browser : browsers) {
			try {
				// Invoke the browser command with the URL parameter
				Process process = Runtime.getRuntime().exec(browser + " " + url);
				if (process.waitFor() != 0) {
					// If an error code is returned, try the next browser in the list.
					continue;
				} else {
					// If a zero result code was returned, the command was successful.
					return true;
				}
			} catch (Exception e) {
				// If an exception is thrown, try next browser in list
				continue;
			}
		}

		// // MessageManager.log("Could not find a browser to use to file Bugzilla bug");
		return false;
	}

	/**
	 * Constructs the comments with the appropriate headings and indentations
	 */
	private String renderComments(String comments) {
		return "Comments: " + LINE_SEP + comments.replaceAll(LINE_SEP, LINE_SEP + "  ") + LINE_SEP;
	}

	/**
	 * Constructs the description with the appropriate headings and indentations
	 */
	public String renderDescription(String abstractText, String issueXml) {
		StringBuilder builder = new StringBuilder();
		builder.append(abstractText);
		builder.append(LINE_SEP);
		builder.append(LINE_SEP);

		String[] lines = issueXml.split("<");
		int startText;
		for (String line : lines) {
			startText = line.indexOf(">") + 1;
			if (line.startsWith("Category>")) {
				builder.append("Category: " + LINE_SEP + "  " + line.substring(startText).trim() + LINE_SEP);
			} else if (line.startsWith("Folder>")) {
				builder.append("Folder: " + LINE_SEP + "  " + line.substring(startText).trim() + LINE_SEP);
			} else if (line.startsWith("Kingdom>")) {
				builder.append("Kingdom: " + LINE_SEP + "  " + line.substring(startText).trim() + LINE_SEP);
			} else if (line.startsWith("Abstract>")) {
				builder.append("Abstract: " + LINE_SEP + "  " + line.substring(startText).trim() + LINE_SEP);
			} else if (line.startsWith("FileName>")) {
				builder.append("FileName: " + LINE_SEP + "  " + line.substring(startText).trim() + LINE_SEP);
			} else if (line.startsWith("Snippet>")) {
				builder.append("Snippet: " + LINE_SEP + "  " + line.substring(startText).trim() + LINE_SEP);
			} else if (line.startsWith("LineStart>")) {
				// replace all line terminators with line.separator
				builder.append("Line: " + LINE_SEP + "  " + line.substring(startText).trim().replaceAll("(?m)$^|[\\r\\n]+\\z", LINE_SEP) + LINE_SEP);
			}
		}
		return builder.toString();
	}
}
